/******************************************************************************/
/*  Class PROCESSOR                                                           */
/*  PO: S. Maslyakov, rusoil.9@gmail.com                                      */
/*                                                                            */
/*  Revision:     1.0                                                         */
/*  Date:         2011/02/15 15:03:33                                         */
/******************************************************************************/


#include "data_types.h"
#include "global_def.h"
#include "Core\core.h"
#include "Fmem_layer\fmem_layer.h"
#include "Device\device.h"
#include "Rfile\rfile.h"
#include "TNKernel\tn.h"
#include "Setpoint\setpoint.h"
#include "Processor\processor.h"




/******************************************************************************/
/*      Kernel data and variables                                             */
/******************************************************************************/
// Task stack
static TN_UINT proc_stack[PROC_STK_SIZE];

// Task struct
static TN_TCB tcb_proc;

// Event
static TN_EVENT proc_event;






//==============================================================================
// App: Init processor
//==============================================================================
void PROCESSOR::Init_Processor() {
    Init_rtos_part();
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Init proc tasks
//==============================================================================
void PROCESSOR::Init_proc_task() {

    // task_proc()
    tcb_proc.id_task = 0;
    tn_task_create(&tcb_proc,                    // task TCB
                   &Task_proc,                   // task function
                   TASK_PROC_PRIORITY,           // task priority
                   &(proc_stack                  // task stack first addr in memory
                      [PROC_STK_SIZE - 1]),
                   PROC_STK_SIZE,                // task stack size (in int,not bytes)
                   NULL,                         // task function parameter
                   0                             // Creation option
                   );
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Init rtos part
//==============================================================================
void PROCESSOR::Init_rtos_part() {
    // Create proc_event
    proc_event.id_event = 0;
    tn_event_create(&proc_event,                              // Ptr to already existing TN_EVENT
                    TN_EVENT_ATTR_SINGLE|TN_EVENT_ATTR_CLR,   // Attribute event
                    0UL                                       // Pattern initial value
                   );
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get proc event
//==============================================================================
void * PROCESSOR::Get_proc_event() {
    return &proc_event;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Activate tasks for proc
//==============================================================================
void PROCESSOR::Activate_proc_task() {

    // task_proc()
    tn_task_activate(&tcb_proc);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: PlusUU
//==============================================================================
void PROCESSOR::PlusUU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 += _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus2
//==============================================================================
void PROCESSOR::PlusUS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 += _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus3
//==============================================================================
void PROCESSOR::PlusUF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 = (uint32_t)(_s->dataF + ((float32_t)_f->data32));
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus4
//==============================================================================
void PROCESSOR::PlusSU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 += _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus5
//==============================================================================
void PROCESSOR::PlusSS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 += _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus6
//==============================================================================
void PROCESSOR::PlusSF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 = (sint32_t)(_s->dataF + ((float32_t)_f->sdata32));
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus7
//==============================================================================
void PROCESSOR::PlusFU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF += (float32_t)_s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus8
//==============================================================================
void PROCESSOR::PlusFS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF += (float32_t)_s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Plus9
//==============================================================================
void PROCESSOR::PlusFF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF += _s->dataF;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus1
//==============================================================================
void PROCESSOR::MinusUU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 -= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus2
//==============================================================================
void PROCESSOR::MinusUS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 -= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus3
//==============================================================================
void PROCESSOR::MinusUF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 -= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus4
//==============================================================================
void PROCESSOR::MinusSU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 -= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus5
//==============================================================================
void PROCESSOR::MinusSS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 -= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus6
//==============================================================================
void PROCESSOR::MinusSF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 = (sint32_t)(((float32_t)(_f->sdata32)) - _s->dataF);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus7
//==============================================================================
void PROCESSOR::MinusFU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF -= (float32_t)(_s->data32);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus8
//==============================================================================
void PROCESSOR::MinusFS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF -= (float32_t)(_s->sdata32);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Minus9
//==============================================================================
void PROCESSOR::MinusFF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF -= _s->dataF;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy1
//==============================================================================
void PROCESSOR::MultyUU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 *= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy2
//==============================================================================
void PROCESSOR::MultyUS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 *= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy3
//==============================================================================
void PROCESSOR::MultyUF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 = (uint32_t)(_s->dataF * _f->data32);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy4
//==============================================================================
void PROCESSOR::MultySU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 *= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy5
//==============================================================================
void PROCESSOR::MultySS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 *= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy6
//==============================================================================
void PROCESSOR::MultySF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 = (sint32_t)(_s->dataF * _f->sdata32);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy7
//==============================================================================
void PROCESSOR::MultyFU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF *= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy8
//==============================================================================
void PROCESSOR::MultyFS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF *= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Multy9
//==============================================================================
void PROCESSOR::MultyFF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF *= _s->dataF;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide1
//==============================================================================
void PROCESSOR::DivideUU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 /= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide2
//==============================================================================
void PROCESSOR::DivideUS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 /= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide3
//==============================================================================
void PROCESSOR::DivideUF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->data32 = (uint32_t)(((float32_t)_f->data32) / _s->dataF);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide4
//==============================================================================
void PROCESSOR::DivideSU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 /= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide5
//==============================================================================
void PROCESSOR::DivideSS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 /= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide6
//==============================================================================
void PROCESSOR::DivideSF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->sdata32 = (sint32_t)(((float32_t)_f->sdata32) / _s->dataF);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide7
//==============================================================================
void PROCESSOR::DivideFU(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF /= _s->data32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide8
//==============================================================================
void PROCESSOR::DivideFS(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF /= _s->sdata32;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Divide9
//==============================================================================
void PROCESSOR::DivideFF(__UNION_DWORD * _f, const __UNION_DWORD * _s) {
    _f->dataF /= _s->dataF;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Run plus func
//==============================================================================
void PROCESSOR::RunPlusFunc(const uint32_t _ind,
                            __UNION_DWORD * _f,
                            const __UNION_DWORD * _s) {
    static void (* const pPlus[9]) (__UNION_DWORD *, const __UNION_DWORD *) =
    {
        PlusUU, PlusUS, PlusUF,
        PlusSU, PlusSS, PlusSF,
        PlusFU, PlusFS, PlusFF
    };

    // Run
    if (_ind < 9) {
        (pPlus[_ind])(_f, _s);
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Run minus func
//==============================================================================
void PROCESSOR::RunMinusFunc(const uint32_t _ind,
                             __UNION_DWORD * _f,
                             const __UNION_DWORD * _s) {
    static void (* const pMinus[9]) (__UNION_DWORD *, const __UNION_DWORD *) =
    {
        MinusUU, MinusUS, MinusUF,
        MinusSU, MinusSS, MinusSF,
        MinusFU, MinusFS, MinusFF
    };

    // Run
    if (_ind < 9) {
        (pMinus[_ind])(_f, _s);
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Run multy func
//==============================================================================
void PROCESSOR::RunMultyFunc(const uint32_t _ind,
                             __UNION_DWORD * _f,
                             const __UNION_DWORD * _s) {
    static void (* const pMulty[9]) (__UNION_DWORD *, const __UNION_DWORD *) =
    {
        MultyUU, MultyUS, MultyUF,
        MultySU, MultySS, MultySF,
        MultyFU, MultyFS, MultyFF
    };

    // Run
    if (_ind < 9) {
        (pMulty[_ind])(_f, _s);
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Run divide func
//==============================================================================
void PROCESSOR::RunDivideFunc(const uint32_t _ind,
                              __UNION_DWORD * _f,
                              const __UNION_DWORD * _s) {
    static void (* const pDivide[9]) (__UNION_DWORD *, const __UNION_DWORD *) =
    {
        DivideUU, DivideUS, DivideUF,
        DivideSU, DivideSS, DivideSF,
        DivideFU, DivideFS, DivideFF
    };

    // Run
    if (_ind < 9) {
        (pDivide[_ind])(_f, _s);
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get data size
//==============================================================================
uint32_t PROCESSOR::GetDataSize(const uint32_t _dataType) {
    switch (_dataType)
    {
        //----------------------------------------------------------------------
        case eDCELL_UINT8:
        //----------------------------------------------------------------------
        case eDCELL_SINT8:
          return 1;

        //----------------------------------------------------------------------
        case eDCELL_UINT16:
        //----------------------------------------------------------------------
        case eDCELL_SINT16:
          return 2;

        //----------------------------------------------------------------------
        case eDCELL_UINT32:
        //----------------------------------------------------------------------
        case eDCELL_SINT32:
        //----------------------------------------------------------------------
        case eDCELL_FLOAT32:
          return 4;

        //----------------------------------------------------------------------
        default:
          return 0;
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Get func ind
//==============================================================================
uint32_t PROCESSOR::GetFuncInd(const uint32_t _type) {
    switch (_type)
    {
        //----------------------------------------------------------------------
        case eDCELL_UINT8:
        //----------------------------------------------------------------------
        case eDCELL_UINT16:
        //----------------------------------------------------------------------
        case eDCELL_UINT32:
          return 0;

        //----------------------------------------------------------------------
        case eDCELL_SINT8:
        //----------------------------------------------------------------------
        case eDCELL_SINT16:
        //----------------------------------------------------------------------
        case eDCELL_SINT32:
          return 1;

        //----------------------------------------------------------------------
        case eDCELL_FLOAT32:
          return 2;

        //----------------------------------------------------------------------
        default:
          return 0;
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Convert signed data
//==============================================================================
void PROCESSOR::ConvertSignData(const uint32_t _type,
                                __UNION_DWORD * const _pData) {

    __UNION_DWORD temp;

    switch (_type)
    {
        //----------------------------------------------------------------------
        case eDCELL_SINT8:
          temp.sdata32 = (sint32_t)(_pData->sdata8[0]);
          _pData->sdata32 = temp.sdata32;
        break;

        //----------------------------------------------------------------------
        case eDCELL_SINT16:
          temp.sdata32 = (sint32_t)(_pData->sdata16[0]);
          _pData->sdata32 = temp.sdata32;
        break;

        //----------------------------------------------------------------------
        default:
        break;
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Read action record
//==============================================================================
uint32_t PROCESSOR::ReadRec(__ACTION_SETT_PROC * const _pRec,
                            const uint32_t _index) {
    __FMEM_DATA mem;
    uint32_t err;

    // Test
    if (_index > (MEM_DPROC_NUM - 1)) {
        return eMEM_ADDR_ERROR;
    };

    // Read
    mem.addr = MEM_DPROC_BL_START + _index * sizeof(__ACTION_SETT_PROC);
    mem.dataLen = sizeof(__ACTION_SETT_PROC);
    mem.pBuff = (uint8_t *)_pRec;

    for (uint32_t i = 0; i < 3; i++) {
        err = DEVICE::ReadSett(&mem);
        if (err == eMEM_OK) {
            break;
        };
        tn_task_sleep(TN_MSEC_TO_TICK(50));
    };

    return err;
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Read arguments from reg file
//==============================================================================
bool_t PROCESSOR::ReadArg(const __CELL_PROC * const _pCell,
                          __UNION_DWORD * const _pDst) {

    if (_pCell->type.tcell == eTCELL_ADDR) {
        __RFILE_DATA data;

        // Read data from reg file
        data.addr = _pCell->cell;
        data.pBuff = _pDst->data8;
        data.dataLen = GetDataSize(_pCell->type.dcell);

        return RFILE::ReadRfile(&data);
    }
    else if (_pCell->type.tcell == eTCELL_CONST) {
        // Copy const in dst
        _pDst->data32 = _pCell->cell;
        return TRUE_T;
    }
    else {
        return FALSE_T;
    };
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Save result in reg file
//==============================================================================
void PROCESSOR::SaveResult(const __CELL_PROC * const _pCell,
                           __UNION_DWORD * const _pSrc) {

    if (_pCell->type.tcell != eTCELL_ADDR) {
        return;
    };

    __RFILE_DATA data;

    data.addr = _pCell->cell;
    data.pBuff = _pSrc->data8;
    data.dataLen = GetDataSize(_pCell->type.dcell);

    RFILE::WriteRfile(&data);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Perform action
//==============================================================================
void PROCESSOR::PerfomAction(const __ACTION_SETT_PROC * const _pRec) {
    __UNION_DWORD data_f;
    __UNION_DWORD data_s;
    uint32_t ind;

    // Test
    if ((_pRec->cell_f.type.tcell == eTCELL_ADDR)
          && (_pRec->cell_f.cell > RFMEM_END)) {
        return;
    };

    if ((_pRec->cell_s.type.tcell == eTCELL_ADDR)
          && (_pRec->cell_s.cell > RFMEM_END)) {
        return;
    };

    if ((_pRec->cell_res.cell < RFMEM_USER_MEM_ST)
          && (_pRec->cell_res.cell > RFMEM_END)) {
        return;
    };

    // Read arguments
    if (ReadArg(&(_pRec->cell_f), &data_f) == FALSE_T) {
        return;
    };

    if (_pRec->action != ePACT_COPY) {
        if (ReadArg(&(_pRec->cell_s), &data_s) == FALSE_T) {
            return;
        };
    };

    // Get func index
    ind = 3 * GetFuncInd(_pRec->cell_f.type.dcell);
    ind += GetFuncInd(_pRec->cell_s.type.dcell);

    // Convert signed data
    ConvertSignData(_pRec->cell_f.type.dcell, &data_f);
    ConvertSignData(_pRec->cell_s.type.dcell, &data_s);

    // Apply action
    switch (_pRec->action)
    {
        //----------------------------------------------------------------------
        case ePACT_COPY:
        break;

        //----------------------------------------------------------------------
        case ePACT_PLUS:
          RunPlusFunc(ind, &data_f, &data_s);
        break;

        //----------------------------------------------------------------------
        case ePACT_MINUS:
          RunMinusFunc(ind, &data_f, &data_s);
        break;

        //----------------------------------------------------------------------
        case ePACT_MULTY:
          RunMultyFunc(ind, &data_f, &data_s);
        break;

        //----------------------------------------------------------------------
        case ePACT_DIVIDE:
          RunDivideFunc(ind, &data_f, &data_s);
        break;

        //----------------------------------------------------------------------
        case ePACT_AND:
          data_f.data32 &= data_s.data32;
        break;

        //----------------------------------------------------------------------
        case ePACT_OR:
          data_f.data32 |= data_s.data32;
        break;

        //----------------------------------------------------------------------
        default:
        return;
    };

    // Save result
    SaveResult(&_pRec->cell_res, &data_f);
}
//==============================================================================
//==============================================================================


//==============================================================================
// App: Task task_proc()
//==============================================================================
void PROCESSOR::Task_proc(void * par) {

    while (1) {

        // Proccessing data routine
        for (uint32_t i = 0; i < MEM_DPROC_NUM; i++) {
            __ACTION_SETT_PROC act;

            // Read action
            if (ReadRec(&act, i) != eMEM_OK) {
                break;
            };

            // Test flag
            if (act.isCellEn != PROCESS_DATA_EN_FLG) {
                break;
            };

            // Perfom
            PerfomAction(&act);
        };

        // Send event
        tn_event_set(&proc_event, PROCESS_DATA_END_EVENT);

        // Exit task
        tn_task_exit(0);
    };
}
//==============================================================================
//==============================================================================